//---------------------------------------------------------------------
//Copyright (c) 2009, Pierre Milet
//All rights reserved.
//
//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
//INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
//IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 
//OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
//PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
//TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
//---------------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Text.RegularExpressions;
using System.Threading;
using System.Data.SqlClient;
using System.Data;
using System.Xml;
using System.Collections;
using System.Linq;
using System.Configuration;
using BizMock.Adapter.Runtime;
using Application = Microsoft.BizTalk.ExplorerOM.Application;
using ApplicationCollection = Microsoft.BizTalk.ExplorerOM.ApplicationCollection;
using System.Diagnostics;
using Microsoft.Samples.BizTalk.Adapter.Common;
using Microsoft.BizTalk.Message.Interop;
using Microsoft.XLANGs.BaseTypes;


namespace BizMock
{   
    public sealed class BizMockery
    {
        #region variables        
        static BizMockery _instance;
        private BizMockReceiver _receiver;
        private string _bizMockFileInterchangePath = string.Format("{0}\\{1}", System.Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData), @"BizMock");

        #endregion

        #region public
        
        BizMockery( )
        {
           
            _receiver = new BizMockReceiver();

            string directoryPath = string.Format("{0}\\{1}", System.Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData), @"BizMock"); ;
            if ( !Directory.Exists( directoryPath ) )
                Directory.CreateDirectory( directoryPath );

            string[] files = Directory.GetFiles( directoryPath );
            foreach ( string file in files )
            {
                File.Delete( file );
            }
        }      
     
        public static BizMockery Instance
        {
            get
            {
                if (_instance == null)
                    _instance = new BizMockery();
                return _instance;
            }
        }

        public static void Reset(bool deleteAllInstances)
        {
            _instance = new BizMockery( );
            if( deleteAllInstances )
                DeleteAllInstances();
        }
       
        public static void DeleteAllInstances()
        {
            BizTalkExplorerHelper.DeleteAllInstances();
        }
      
        public void SubmitRequest( string uri, Message request )
        {
            _receiver.ProcessRequest( "bizmock://" + uri, request );
        }

        public void SubmitResponse( string uri, Message response )
        {
            _receiver.ProcessResponse( uri, response );
        }

        public void GetResponse( string uri )
        {
            _receiver.GetResponse( uri);
        }

        public string[] GetBizMockContextFiles(string uri, string messageType)
        {
            string searchPattern = string.Format("*{0}_{1}*ctx*", uri, messageType);
            return Directory.GetFiles(_bizMockFileInterchangePath, searchPattern);
        }

        public List<string[]> GetBizMockMessageFiles(string uri, string messageType)
        {
            List<string[]> messages = new List<string[]>();
            string searchPattern = string.Format("*{0}_{1}*ctx*", uri, messageType);
            string [] files = Directory.GetFiles( _bizMockFileInterchangePath, searchPattern );
            foreach (string file in files)
            {
                searchPattern = file.Replace("ctx", "msg");
                searchPattern = searchPattern.Replace(".xml", "*");
                searchPattern = searchPattern.Replace(_bizMockFileInterchangePath+"\\", "");
                string[] parts = Directory.GetFiles(_bizMockFileInterchangePath,searchPattern);
                if( parts.Length > 0 )
                    messages.Add(parts); 
            }
            return messages;
        }
     
        public void ValidateMessageContents( string[] files, MessageVerifierBase messageVerifier)
        {
            IMultiPartVerifier multipartVerifier = null;
            if ( messageVerifier is IMultiPartVerifier )
            {
                multipartVerifier = messageVerifier as IMultiPartVerifier;
                if ( files.Length != multipartVerifier.Verifiers.Length )
                    throw new BizMockException("unexpected number of parts");
                for (int i = 0; i < files.Length; i++)
                {
                    IBaseMessage msg = MessageFileHelper.LoadFromBodyContentsFile( files[i], new BizMockMessageFactory());
                    foreach (BizMockMessageValidationAction va in multipartVerifier.Verifiers[i].ValidationDelegates)
                    {
                        va.Invoke(msg);
                    }
                }
            }
            else
            {
                if( files.Length > 1 )
                    throw new BizMockException("expected a non multipart message");            
                IBaseMessage msg = MessageFileHelper.LoadFromBodyContentsFile(files[0], new BizMockMessageFactory());
                foreach (BizMockMessageValidationAction va in messageVerifier.ValidationDelegates)
                {
                    va.Invoke(msg);
                }
            }
        }

        public void ValidateEventLog( string source, MessageVerifierBase messageVerifier )
        {
            IEnumerable<string> messages = EventLog.GetEventLogs().First<EventLog>().Entries.OfType<EventLogEntry>().Where<EventLogEntry>(x => x.Source == source).Select<EventLogEntry, string>(x => x.Message);
            bool verified = false;
            string errors = "event not found";
            foreach (string message in messages)
            {
                IBaseMessage bmsg = MessageFileHelper.LoadFromBodyContentsString(message, new BizMockMessageFactory());
                foreach (BizMockMessageValidationAction valfunc in messageVerifier.ValidationDelegates)
                {
                    try
                    {
                        errors = string.Empty;
                        valfunc.Invoke(bmsg);
                        verified = true;
                        return;
                    }
                    catch (Exception e)
                    {
                        if (errors != "" )
                        {
                            errors += ":" + e.Message;
                        }
                        else
                        {
                            errors = e.Message;
                        }
                        verified = false;
                        continue;
                    }                    
                }                
            }
            if( !verified )
                throw new BizMockException( errors ); ;
            return;
       }

       public string[] Transform(string[] files, TransformBase map)
       {
            string[] transformedFiles = new string[files.Length];
            int i = 0;
            foreach (string file in files)
            {
                using (Stream outputStream = new MemoryStream())
                {
                    XmlDocument input = new XmlDocument();
                    input.Load(file);

                    XmlWriter output = new XmlTextWriter(outputStream, Encoding.UTF8);

                    map.Transform.Transform(input, map.TransformArgs, outputStream);

                    outputStream.Position = 0;
                    input.Load(outputStream);
                    string transformedFile = "X_" + file;
                    input.Save(transformedFile);
                    transformedFiles[i++] = transformedFile;
                }
            }
            return transformedFiles;
        }

        #endregion
      

    }
}